package com.codedancer.campus.manager.service.impl;

import cn.afterturn.easypoi.entity.vo.NormalExcelConstants;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.view.PoiBaseView;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.codedancer.campus.common.exception.BusinessException;
import com.codedancer.campus.common.utils.HttpClientUtil;
import com.codedancer.campus.common.utils.UUIDGenerator;
import com.codedancer.campus.enums.CircleStatus;
import com.codedancer.campus.enums.SystemMessageType;
import com.codedancer.campus.manager.mq.producer.MqSendMessageProducer;
import com.codedancer.campus.manager.service.ICircleService;
import com.codedancer.campus.manager.service.bo.circle.CircleExamineBo;
import com.codedancer.campus.manager.service.bo.circle.CirclePageSearchBo;
import com.codedancer.campus.manager.service.excel.CircleExcel;
import com.codedancer.campus.manager.service.model.SystemMessageMqParamModel;
import com.codedancer.campus.manager.service.vo.circle.CirclePageVo;
import com.codedancer.campus.manager.service.vo.circle.CircleVo;
import com.codedancer.campus.mapper.CircleExamineRecordMapper;
import com.codedancer.campus.mapper.CircleFollowMapper;
import com.codedancer.campus.mapper.CircleLabelMapper;
import com.codedancer.campus.mapper.CircleMapper;
import com.codedancer.campus.mapper.SchoolMapper;
import com.codedancer.campus.mapper.SystemMessageMapper;
import com.codedancer.campus.mapper.UserMapper;
import com.codedancer.campus.po.Circle;
import com.codedancer.campus.po.CircleExamineRecord;
import com.codedancer.campus.po.CircleLabel;
import com.codedancer.campus.po.School;
import com.codedancer.campus.po.User;
import com.codedancer.campus.qo.circle.CirclePageSearchQo;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class CircleServiceImpl implements ICircleService {

    @Autowired
    private CircleMapper circleMapper;
    @Autowired
    private SchoolMapper schoolMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private CircleLabelMapper circleLabelMapper;
    @Autowired
    private SystemMessageMapper systemMessageMapper;
    @Autowired
    private CircleExamineRecordMapper circleExamineRecordMapper;
    @Autowired
    private CircleFollowMapper circleFollowMapper;
    @Autowired
    private MqSendMessageProducer mqSendMessageProducer;

    /**
     * 分页查询圈子
     *
     * @param circlePageSearchBo
     * @return
     */
    @Override
    public IPage<CirclePageVo> page(CirclePageSearchBo circlePageSearchBo) {
        CirclePageSearchQo circlePageSearchQo = BeanUtil
            .copyProperties(circlePageSearchBo, CirclePageSearchQo.class);
        circlePageSearchQo.setSchoolUuid(circlePageSearchBo.getCreateSchoolUuid());
        IPage<Circle> circleIPage = circleMapper.page2Manager(
            new Page<Circle>(circlePageSearchBo.getPage(), circlePageSearchBo.getSize()),
            circlePageSearchQo);
        List<CirclePageVo> circlePageVos;
        IPage<CirclePageVo> circlePageVoIPage = new Page<>();
        circlePageVos = circleIPage.getRecords().stream().map(circle -> {
            CirclePageVo circlePageVo = BeanUtil.copyProperties(circle, CirclePageVo.class);
            School school = schoolMapper.findById(circle.getCreateSchoolUuid())
                .orElseThrow(
                    () -> new BusinessException("圈子学校不存在，圈子标题：" + circle.getTitle()));
            circlePageVo.setCreateSchoolName(school.getName());
            User user = userMapper.selectById(circle.getCreateUserUuid());
            circlePageVo.setCreateUserNickName(user.getNickName());
            // 查询该圈子的标签
            List<CircleLabel> circleLabels = circleLabelMapper
                .selectListByColumn("circle_uuid", circle.getUuid());
            circlePageVo.setLabels(circleLabels.stream().map(CircleLabel::getName).collect(
                Collectors.toList()));
            return circlePageVo;
        }).collect(Collectors.toList());
        circlePageVoIPage.setTotal(circleIPage.getTotal());
        circlePageVoIPage.setRecords(circlePageVos);
        return circlePageVoIPage;
    }

    /**
     * 启用圈子
     *
     * @param uuid
     */
    @Override
    public void enable(String uuid) {
        Circle circle = circleMapper.findById(uuid)
            .orElseThrow(() -> new BusinessException("圈子不存在"));
        circle.setDisabled(false);
        circleMapper.updateById(circle);
    }

    /**
     * 禁用圈子
     *
     * @param uuid
     */
    @Override
    public void disable(String uuid) {
        Circle circle = circleMapper.findById(uuid)
            .orElseThrow(() -> new BusinessException("圈子不存在"));
        circle.setDisabled(true);
        circleMapper.updateById(circle);
    }

    /**
     * 删除圈子
     *
     * @param uuid
     */
    @Override
    public void delete(String uuid) {
        // 删除圈子关联的数据信息
        // 删除用户关注的圈子
        circleFollowMapper.deleteByColumn("circle_uuid", uuid);
        circleMapper.deleteById(uuid);
    }

    /**
     * 导出圈子
     *
     * @param request
     * @param response
     * @param circlePageSearchBo
     */
    @Override
    public void export(HttpServletRequest request, HttpServletResponse response,
        CirclePageSearchBo circlePageSearchBo) {
        log.info("开始导出圈子数据");
        CirclePageSearchQo circlePageSearchQo = BeanUtil
            .copyProperties(circlePageSearchBo, CirclePageSearchQo.class);
        // 查询需要导出的数据
        List<Circle> circles = circleMapper.listExportData(circlePageSearchQo);
        // 组装数据
        List<CircleExcel> circleExcels = assembleData(circles);
        Map<String, Object> map = new HashMap<>();
        ExportParams params = new ExportParams("圈子列表", "圈子列表", ExcelType.HSSF);
        map.put(NormalExcelConstants.DATA_LIST, circleExcels);
        map.put(NormalExcelConstants.CLASS, CircleExcel.class);
        map.put(NormalExcelConstants.PARAMS, params);
        map.put(NormalExcelConstants.FILE_NAME, "圈子列表" + DateUtil.today());
        PoiBaseView.render(map, request, response, NormalExcelConstants.EASYPOI_EXCEL_VIEW);
        log.info("导出圈子数据完成");
    }

    /**
     * 批量启用
     *
     * @param uuids
     */
    @Override
    public void batchEnable(List<String> uuids) {
        for (String uuid : uuids) {
            Circle circle = circleMapper.findById(uuid)
                .orElseThrow(() -> new BusinessException("圈子不存在，uuid：" + uuid));
            circle.setDisabled(false);
            circleMapper.updateById(circle);
        }
    }

    /**
     * 批量禁用
     *
     * @param uuids
     */
    @Override
    public void batchDisable(List<String> uuids) {
        for (String uuid : uuids) {
            Circle circle = circleMapper.findById(uuid)
                .orElseThrow(() -> new BusinessException("圈子不存在，uuid：" + uuid));
            circle.setDisabled(true);
            circleMapper.updateById(circle);
        }
    }

    /**
     * 批量删除
     *
     * @param uuids
     */
    @Override
    public void batchDelete(List<String> uuids) {
        circleMapper.deleteBatchIds(uuids);
    }

    /**
     * 通过审核
     *
     * @param circleExamineBo
     */
    @Override
    public void pass(CircleExamineBo circleExamineBo) {
        Circle circle = circleMapper.findById(circleExamineBo.getUuid())
            .orElseThrow(() -> new BusinessException("圈子不存在"));
        circle.setDisabled(false);
        circle.setStatus(CircleStatus.PASSED);
        circleMapper.updateById(circle);
        // 保存审核记录
        CircleExamineRecord circleExamineRecord = CircleExamineRecord.builder()
            .uuid(UUIDGenerator.getUUID())
            .circleUuid(circle.getUuid())
            .examineAdminUuid(circleExamineBo.getCurrentUserUuid())
            .isPass(true).build();
        circleExamineRecordMapper.insert(circleExamineRecord);
        SystemMessageMqParamModel systemMessageMqParamModel = SystemMessageMqParamModel.builder()
            .messageType(SystemMessageType.CIRCLE_EXAMINE)
            .content("【" + circle.getTitle() + "】审核通过")
            .receiveUserUuid(circle.getCreateUserUuid()).build();
        mqSendMessageProducer.sendSystemMessage(JSONUtil.toJsonStr(systemMessageMqParamModel));
    }

    /**
     * 未通过审核
     *
     * @param circleExamineBo
     */
    @Override
    public void noPass(CircleExamineBo circleExamineBo) {
        Circle circle = circleMapper.findById(circleExamineBo.getUuid())
            .orElseThrow(() -> new BusinessException("圈子不存在"));
        circle.setStatus(CircleStatus.NOT_PASS);
        circleMapper.updateById(circle);
        // 保存审核记录
        CircleExamineRecord circleExamineRecord = CircleExamineRecord.builder()
            .uuid(UUIDGenerator.getUUID())
            .circleUuid(circle.getUuid())
            .examineAdminUuid(circleExamineBo.getCurrentUserUuid())
            .noPassReason(circleExamineBo.getNoPassReason())
            .isPass(false).build();
        circleExamineRecordMapper.insert(circleExamineRecord);
        // 保存系统消息
        SystemMessageMqParamModel systemMessageMqParamModel = SystemMessageMqParamModel.builder()
            .messageType(SystemMessageType.CIRCLE_EXAMINE)
            .content(
                "【" + circle.getTitle() + "】审核未通过，原因为：" + circleExamineBo.getNoPassReason())
            .receiveUserUuid(circle.getCreateUserUuid()).build();
        mqSendMessageProducer.sendSystemMessage(JSONUtil.toJsonStr(systemMessageMqParamModel));
    }

    /**
     * 获取圈子详情
     *
     * @param uuid
     * @return
     */
    @Override
    public CircleVo detail(String uuid) {
        Circle circle = circleMapper.findById(uuid)
            .orElseThrow(() -> new BusinessException("圈子不存在"));
        CircleVo circleVo = BeanUtil.copyProperties(circle, CircleVo.class);
        User user = userMapper.selectById(circle.getCreateUserUuid());
        circleVo.setCreateUserNickName(user.getNickName());
        School school = schoolMapper.selectById(circle.getCreateSchoolUuid());
        circleVo.setCreateSchoolName(school.getName());
        // 获取绑定的标签
        List<CircleLabel> circleLabels = circleLabelMapper.selectListByColumn("circle_uuid", uuid);
        circleVo.setLabels(
            circleLabels.stream().map(CircleLabel::getName).collect(Collectors.toList()));
        // 查询最近一条审核记录
        CircleExamineRecord circleExamineRecord = circleExamineRecordMapper
            .selectLatestExamineRecord(uuid);
        if (ObjectUtil.isNotEmpty(circleExamineRecord)) {
            circleVo.setLatestNoPassReason(circleExamineRecord.getNoPassReason());
        }
        return circleVo;
    }

    /**
     * 组装数据 将Circle转化为CircleExcle
     *
     * @param circles
     * @return
     */
    private List<CircleExcel> assembleData(List<Circle> circles) {
        return circles.stream().map(circle -> {
            CircleExcel circleExcel = BeanUtil.copyProperties(circle, CircleExcel.class);
            // 设置头像
            byte[] avatar = HttpClientUtil.getImageFromNetByUrl(circle.getAvatar());
            circleExcel.setAvatarUrl(avatar);
            // 设置是否禁用
            circleExcel.setIsDisabled(circle.getDisabled() ? "禁用" : "启用");
            // 设置状态
            circleExcel.setStatus(circle.getStatus().getName());
            // 设置创建人
            User user = userMapper.selectById(circle.getCreateUserUuid());
            circleExcel.setCreateUserNickName(user.getNickName());
            // 设置学校
            School school = schoolMapper.selectById(circle.getCreateSchoolUuid());
            circleExcel.setCreateSchoolName(school.getName());
            return circleExcel;
        }).collect(Collectors.toList());
    }
}
